/*
Copyright 2017 zhpanvip The BannerViewPager Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

package com.zhpan.bannerview.indicator

import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.zhpan.indicator.base.BaseIndicatorView

/**
 * @ author : zhouweibin
 * @ time: 2019/12/18 17:04.
 * @ desc: 选中与未选中的图片长宽可能不一样
 */
class DrawableIndicator @JvmOverloads constructor(
  context: Context?,
  attrs: AttributeSet? = null,
  defStyleAttr: Int = 0
) : BaseIndicatorView(context!!, attrs, defStyleAttr) {
  // 选中时的Bitmap
  private var mCheckedBitmap: Bitmap? = null

  // 未选中时的Bitmap
  private var mNormalBitmap: Bitmap? = null

  // 图片之间的间距
  private var mIndicatorPadding = 0

  // 选中图片的宽度
  private var mCheckedBitmapWidth = 0

  // 选中图片的高度
  private var mCheckedBitmapHeight = 0

  //未选中图片的宽高
  private var mNormalBitmapWidth = 0
  private var mNormalBitmapHeight = 0
  private var mIndicatorSize: IndicatorSize? = null
  private var normalCanResize = true
  private var checkCanResize = true
  override fun onMeasure(
    widthMeasureSpec: Int,
    heightMeasureSpec: Int
  ) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    val maxHeight = mCheckedBitmapHeight.coerceAtLeast(mNormalBitmapHeight)
    val realWidth =
      mCheckedBitmapWidth + (mNormalBitmapWidth + mIndicatorPadding) * (getPageSize() - 1)
    setMeasuredDimension(realWidth, maxHeight)
  }

  override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    if (getPageSize() > 1 && mCheckedBitmap != null && mNormalBitmap != null) {
      for (i in 1 until getPageSize() + 1) {
        var left: Int
        var top: Int
        var bitmap = mNormalBitmap
        val index = i - 1
        when {
          index < getCurrentPosition() -> {
            left = (i - 1) * (mNormalBitmapWidth + mIndicatorPadding)
            top = measuredHeight / 2 - mNormalBitmapHeight / 2
          }
          index == getCurrentPosition() -> {
            left = (i - 1) * (mNormalBitmapWidth + mIndicatorPadding)
            top = measuredHeight / 2 - mCheckedBitmapHeight / 2
            bitmap = mCheckedBitmap
          }
          else -> {
            left = (i - 1) * mIndicatorPadding + (i - 2) * mNormalBitmapWidth + mCheckedBitmapWidth
            top = measuredHeight / 2 - mNormalBitmapHeight / 2
          }
        }
        drawIcon(canvas, left, top, bitmap)
      }
    }
  }

  private fun drawIcon(
    canvas: Canvas,
    left: Int,
    top: Int,
    icon: Bitmap?
  ) {
    if (icon == null) {
      return
    }
    canvas.drawBitmap(icon, left.toFloat(), top.toFloat(), null)
  }

  private fun initIconSize() {
    mCheckedBitmap?.let {
      mIndicatorSize?.let {
        if (mCheckedBitmap!!.isMutable && checkCanResize) {
          mCheckedBitmap!!.width = mIndicatorSize!!.checkedWidth
          mCheckedBitmap!!.height = mIndicatorSize!!.checkedHeight
        } else {
          val width = mCheckedBitmap!!.width
          val height = mCheckedBitmap!!.height
          val scaleWidth = mIndicatorSize!!.checkedWidth.toFloat() / width
          val scaleHeight = mIndicatorSize!!.checkedHeight.toFloat() / height
          val matrix = Matrix()
          matrix.postScale(scaleWidth, scaleHeight)
          mCheckedBitmap = Bitmap.createBitmap(mCheckedBitmap!!, 0, 0, width, height, matrix, true)
        }
      }
      mCheckedBitmapWidth = mCheckedBitmap!!.width
      mCheckedBitmapHeight = mCheckedBitmap!!.height
    }
    mNormalBitmap?.let {
      mIndicatorSize?.let {
        if (mNormalBitmap!!.isMutable && normalCanResize) {
          mNormalBitmap!!.width = mIndicatorSize!!.normalWidth
          mNormalBitmap!!.height = mIndicatorSize!!.normalHeight
        } else {
          val width = mNormalBitmap!!.width
          val height = mNormalBitmap!!.height
          val scaleWidth = mIndicatorSize!!.normalWidth.toFloat() / mNormalBitmap!!.width
          val scaleHeight = mIndicatorSize!!.normalHeight.toFloat() / mNormalBitmap!!.height
          val matrix = Matrix()
          matrix.postScale(scaleWidth, scaleHeight)
          mNormalBitmap = Bitmap.createBitmap(mNormalBitmap!!, 0, 0, width, height, matrix, true)
        }
      }
      mNormalBitmapWidth = mNormalBitmap!!.width
      mNormalBitmapHeight = mNormalBitmap!!.height
    }
  }

  fun setIndicatorDrawable(
    @DrawableRes normalDrawable: Int,
    @DrawableRes checkedDrawable: Int
  ): DrawableIndicator {
    mNormalBitmap = BitmapFactory.decodeResource(resources, normalDrawable)
    mCheckedBitmap = BitmapFactory.decodeResource(resources, checkedDrawable)
    if (mNormalBitmap == null) {
      mNormalBitmap = getBitmapFromVectorDrawable(context, normalDrawable)
      normalCanResize = false
    }
    if (mCheckedBitmap == null) {
      mCheckedBitmap = getBitmapFromVectorDrawable(context, checkedDrawable)
      checkCanResize = false
    }
    initIconSize()
    postInvalidate()
    return this
  }

  fun setIndicatorSize(
    normalWidth: Int,
    normalHeight: Int,
    checkedWidth: Int,
    checkedHeight: Int
  ): DrawableIndicator {
    mIndicatorSize = IndicatorSize(normalWidth, normalHeight, checkedWidth, checkedHeight)
    initIconSize()
    postInvalidate()
    return this
  }

  fun setIndicatorGap(padding: Int): DrawableIndicator {
    if (padding >= 0) {
      mIndicatorPadding = padding
      postInvalidate()
    }
    return this
  }

  internal class IndicatorSize(
    var normalWidth: Int,
    var normalHeight: Int,
    var checkedWidth: Int,
    var checkedHeight: Int
  )

  private fun getBitmapFromVectorDrawable(
    context: Context,
    drawableId: Int
  ): Bitmap? {
    var drawable = ContextCompat.getDrawable(context, drawableId)
    drawable?.let {
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable!!)
          .mutate()
      }
      val bitmap = Bitmap.createBitmap(
        drawable!!.intrinsicWidth,
        drawable!!.intrinsicHeight, Bitmap.Config.ARGB_8888
      )
      val canvas = Canvas(bitmap)
      drawable!!.setBounds(0, 0, canvas.width, canvas.height)
      drawable!!.draw(canvas)
      return bitmap
    }
    return null
  }
}